/*
 * @Author: 迟天祎 3605405300@qq.com
 * @Date: 2025-06-27 10:17:20
 * @LastEditors: 迟天祎 3605405300@qq.com
 * @LastEditTime: 2025-06-29 11:45:33
 * @FilePath: \23见习2\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import javax.script.ScriptEngineManager;
import java.awt.Color; 
import java.awt.Dimension;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

//import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import javax.swing.Timer;
import java.util.Date;
import java.text.SimpleDateFormat;

import java.net.URI;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.application.Platform;
import java.io.File;
//继承JFrame 为了直接复用swing框架中窗口管理的能力
//为了子类可以直接调用 JFrame public 的方法

//ApplicationListener  是Java中事件处理机制的核心部分
//为了建立计算器组件和用户操作之间的响应机制
public class Calculator extends JFrame implements ActionListener {
    // 声明界面组件
    // 上下两个注释面板 上面是文本框区域 下面是按钮区域
    private JPanel north, center;
    // 文本框 显示计算过程、结果或者日期时间
    private JTextField field;
    // 按钮
    private JButton[] btns;
    // 标记当前是否显示时间 // 新增：时间显示状态标记
    private boolean isShowingTime = false;
    // 保存计算前的表达式，用于时间显示后恢复 // 新增：保存表达式的变量
    private String previousExpression = "";
    // 时间定时器
    private javax.swing.Timer timeTimer; 
    // 时间更新状态标记
    private boolean isTimeUpdating = false; 

    // 背景音乐相关变量
    private MediaPlayer backgroundMusicPlayer;  // 媒体播放器
    private boolean isMusicPlaying =false;  // 播放状态标记
    //使用正确转义的绝对路径
    private final String MUSIC_PATH ="D:\\迟天祎\\实训  见习2\\23见习2\\Nutag.mp3";
    // 主题相关变量 // 新增：主题系统变量
    private int currentTheme = 0; // 0:默认主题, 1:深色主题, 2:亮色主题
    private final Color[][] themes = {
        // 默认主题：浅灰背景+黑色文字
        {new Color(240, 240, 240), Color.BLACK, new Color(220, 220, 220), Color.BLACK},
        // 深色主题：深粉背景+白色文字
        {new Color(200, 90, 130), Color.WHITE, new Color(180, 70, 110), Color.WHITE},
        // 亮色主题：淡蓝背景+深蓝色文字
        {new Color(200, 230, 255), new Color(30, 70, 120), new Color(150, 200, 230), new Color(20, 50, 100)}
    };

    // 初始化窗口 构造器 构造方法 无参构造器
    public Calculator() {
        //初始化 JavaFx 环境，以便后续使用 MediaPlayer 播放音乐
        JFXPanel fxPanel = new JFXPanel(); //确保MediaPlayer 能正常工作
        // 设置窗口标题
        setTitle("计算器");
        // 设置窗口大小
        setSize(700, 700);
        // 设置窗口关闭时操作
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        // 设置窗口居中显示
        setLocationRelativeTo(null);
        //初始化界面组件
        initComponent();
        // 初始化背景音乐(关键步骤)
        initBackgroundMusic();
        // 设置窗口显示
        setVisible(true);
    }
    //初始化界面组件

    // 初始化背景音乐
    private void initBackgroundMusic() {
        try {
            //检查音乐是否存在
            if (MUSIC_PATH != null && !MUSIC_PATH.isEmpty()) {
                URI uri = new File(MUSIC_PATH).toURI();
                Media media = new Media(uri.toString());
                //初始化播放器
                backgroundMusicPlayer = new MediaPlayer(media);
                //循环播放
                backgroundMusicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
                startBackgroundMusic();
                //关闭窗口时停止音乐  窗口事件监听
                addWindowListener(new java.awt.event.WindowAdapter() {
                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        stopBackgroundMusic();
                    }
                });
            }
        } catch (Exception e) {
            System.err.println("背景音乐初始化失败: " + e.getMessage());
        }
    }

    // 播放背景音乐
    public void startBackgroundMusic() {
        if (backgroundMusicPlayer != null) {
            backgroundMusicPlayer.play();  //启动播放音乐
            isMusicPlaying = true;  //更新状态
        }
    }

    // 停止背景音乐 
    public void stopBackgroundMusic() {
        if (backgroundMusicPlayer != null) {
            backgroundMusicPlayer.stop();
            isMusicPlaying = false;
        }
    }

    // 切换背景音乐播放状态
    public void toggleBackgroundMusic() {
        if (isMusicPlaying) { //查看音乐是否在播放  执行语句
            stopBackgroundMusic();
        } else {
            startBackgroundMusic();
        }
    }

    // 初始化组件
    private void initComponent(){
        //System.out.println("initComponent");
        //创建面板容器
        // 上下两个注释面板 上面是文本框区域 下面是按钮区域
        north = new JPanel();
        center = new JPanel();
        // 文本框 显示计算过程、结果或者日期时间
        field = new JTextField();
        //设置输入框大小  首选尺寸
        field.setPreferredSize(new Dimension(700,150));
        //禁用文字输入  禁止通过电脑键盘输入编辑
        field.setEditable(false);
        //设置输入框文字大小
        field.setFont(new Font("SansSerif",Font.BOLD,35));
        // 按钮文本内容
        // JButton[] btns;
        String[] str = new String[]{
            "7","8","9","+",
            "4","5","6","-",
            "1","2","3","×",  //考虑使用者体验
            "0",".","=","÷",
            "C","B","T","S",
            "播放","音乐","暂停","退出"
        };
        //按钮数组
        btns = new JButton[str.length];
        for(int i = 0;i < btns.length; i++){
            btns[i] = new JButton(str[i]);
            //定义Font
            btns[i].setFont(new Font("SansSerif",Font.BOLD,25));

        }
        //将组件放到窗口中
        //设置布局管理器
        //north 顶部面板 使用 BorderLayout() 边界布局
        north.setLayout(new BorderLayout());
        //center 中间面板 使用 5行4列 的 网格布局
        center.setLayout(new GridLayout(6,4));
        //组件设置
        //field 文本框添加到 north 顶部面板 使用 BorderLayout.CENTER 居中
        north.add(field,BorderLayout.CENTER);
        //btns 按钮添加到 center 面板 增强for循环
        for (JButton btn : btns){
            //通过遍历将所有按钮添加到center面板
            center.add(btn);
        }
        //将 north 顶部面板  添加到窗口中
        add(north,BorderLayout.NORTH);  //按照东南西北布局方式
        //将 center 面板  添加到窗口中
        add(center);
        
        //绑定按钮的监听事件
        for (JButton btn : btns){
            //this 代表当前对象实例
            btn.addActionListener(this);
        }

        // 初始化时间定时器（每秒更新一次）
        timeTimer = new javax.swing.Timer(1000, e -> { 
            if (isShowingTime) {
                updateRealTime(); // 仅在显示时间时更新
            }
        });
        timeTimer.setRepeats(true);
        
        // 窗口关闭时释放定时器资源
        addWindowListener(new java.awt.event.WindowAdapter() {
            @Override
            public void windowClosing(java.awt.event.WindowEvent e) {
                timeTimer.stop();
                System.exit(0);
            }
        });

    }
    
    //处理按键文本
    private void setBtnText(String text){
        //System.out.println("text length:" + text.length);
        //System.out.println("field text length:" + field.getText().length());
        switch(text){
            case "C":
                //清空功能
                field.setText("");
                System.out.println("清除");
                //field.setText(null);  //清除键 按下C 清空文本框 则令其为空
                break;
            case "B":
                //退格功能
                //1.获取输入框内容
                String numText = field.getText();
                //两种情况   
                // 判断是否为空方法  isEmpty(boolean 类型)  或.length
                if (numText.length() != 0){
                    //输入框文本内容不为空
                    //System.out.println("输入框的内容不为空："+numText);
                    //numText 的长度-1
                    String lastText = numText.substring(0, numText.length() - 1);
                    //System.out.println("lastText:" + lastText);
                    //将截取后的文本设置到输入框
                    field.setText(lastText);
                }else{
                    //System.out.println("输入框的内容为空");
                }
                System.out.println("退格");
                break;
            case "T":
                System.out.println("T:显示时间");
                showTime();
                break;
            case "S":
                System.out.println("S:切换主题");
                switchTheme();
                break;
            case "=":
                //System.out.println("=:执行计算功能");
                calculate();
                //用户输入正确的公式 1+1 执行计算操作  然后将结果展示到文本框中
                // 用户输入正确的公式 1+1 
                //field.getText();
                // 执行计算操作  

                // 然后将结果展示到文本框中
                //field.setText();
                
                break;
            case "播放":
                startBackgroundMusic();
                break;
            case "暂停":
                stopBackgroundMusic();
                break;
            case "退出":
                System.exit(0); // 正常退出程序
                break;
            default:
                //System.out.println("setBtnText:"+text);
                //按下数字键  要把文字放在输入框中
                //如果之前文本框中有文字 做拼接
                String oldText = field.getText();
                String newText;

                //防止小数点连续出现
                if (text.equals(".") && oldText.contains(".")) {
                     //检查最后一个数字是否已经包含小数点
                     String[] parts = oldText.split("[+\\-×÷]");
                     String lastNumber = parts[parts.length - 1];
                     if (lastNumber.contains(".")) {
                        return;
                     }
                 }
                 
                // [修改] 处理0的特殊情况
                if (text.equals("0")) {
                    // 防止多个前导0（除非有小数点）
                    if (oldText.equals("0")) return;
                    // 允许0出现在小数点后或运算符后
                    if (!oldText.isEmpty()) {
                        char lastChar = oldText.charAt(oldText.length()-1);
                        if (lastChar == '0' && !oldText.contains(".")) return;
                    }
                }

                if (text.equals(".") && oldText.length() == 0 ){
                    newText = "0.";
                }else{
                    newText = oldText + text;  //与之前的数字拼接在一起 
                // 比如开始是1 再输入2 连起来就是12
                }
   
                // 如果是运算符，检查是否需要替换最后一个字符
                if ("+".equals(text) || "-".equals(text) || "×".equals(text) || "÷".equals(text)|| ".".equals(text)) {
                    if (oldText.length() != 0 && 
                    ("+".equals(oldText.substring(oldText.length() - 1)) ||
                    "-".equals(oldText.substring(oldText.length() - 1)) ||
                    "×".equals(oldText.substring(oldText.length() - 1)) ||
                    "÷".equals(oldText.substring(oldText.length() - 1)) ||
                    ".".equals(oldText.substring(oldText.length() - 1)))) {
                    newText = oldText.substring(0, oldText.length() - 1) + text;
                    } 
                }
                field.setText(newText);
                break;
        }
        
    }

    // 在updateRealTime()方法中
    private void updateRealTime() {
        Date now = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        field.setText(formatter.format(now));
    }

    // 显示当前时间 // 新增：核心时间显示方法
    private void showTime() {
        if (!isShowingTime) {
            previousExpression = field.getText(); // 保存当前表达式
            updateRealTime(); // 先更新一次时间
            field.setText(field.getText()); // 触发显示
            isShowingTime = true;
            timeTimer.start(); // 启动时间定时器
            System.out.println("开始显示实时时间");
        } else {
            // 如果已经在显示时间，再次按T恢复表达式
            field.setText(previousExpression);
            isShowingTime = false;
            timeTimer.stop(); // 停止时间定时器
            System.out.println("停止显示时间，恢复计算");
        }
    }

    // 切换主题功能 // 新增：主题切换核心方法
    private void switchTheme() {
        currentTheme = (currentTheme + 1) % themes.length; // 循环切换主题
        applyTheme(currentTheme); // 应用新主题
        
        // 打印当前主题信息
        String themeName;
        switch (currentTheme) {
            case 0: themeName = "默认主题"; break;
            case 1: themeName = "深色主题"; break;
            case 2: themeName = "亮色主题"; break;
            default: themeName = "未知主题";
        }
        System.out.println("切换到: " + themeName);
    }

    // 应用主题样式 // 新增：主题应用方法
    private void applyTheme(int themeIndex) {
        if (themeIndex < 0 || themeIndex >= themes.length) return;
        
        Color bgColor = themes[themeIndex][0];       // 背景色
        Color textColor = themes[themeIndex][1];     // 文本色
        Color btnBgColor = themes[themeIndex][2];    // 按钮背景色
        Color btnTextColor = themes[themeIndex][3];  // 按钮文本色
        
        // 设置窗口和面板背景
        getContentPane().setBackground(bgColor);
        north.setBackground(bgColor);
        center.setBackground(bgColor);
        
        // 设置文本框样式
        field.setBackground(bgColor);
        field.setForeground(textColor);
        
        // 设置按钮样式
        for (JButton btn : btns) {
            btn.setBackground(btnBgColor);
            btn.setForeground(btnTextColor);
            // 增强按钮边框视觉效果
            btn.setOpaque(true);
            btn.setBorderPainted(true);
        }
    }

    //执行计算功能  
    // 用 private 考虑到封装的特性  保证内部的内容 public也可以 
    // 参数可以有也可以没有
    private void calculate(){
        //用户输入正确的公式 1+1 执行计算操作  然后将结果展示到文本框中
        // 用户输入正确的公式 1+1 
        //如果表达式中有 × ÷ 要替换为 * /
        String expression = field.getText(); //从文本框中提取表达式
        //替换× ÷为 * /
        expression = expression.replace("×", "*").replace("÷", "/");
        // 执行计算操作  使用 js 计算引擎
        ScriptEngineManager manager = new ScriptEngineManager();
        //初始化计算引擎  使用javascript解析数学表达式
        ScriptEngine engine = manager.getEngineByName("javascript");
        
        try{
            //开始计算  计算过程可能出现异常 需要处理异常
            Object result = engine.eval(expression);
            // 然后将结果展示到文本框中
            field.setText(result.toString());
        }catch(ScriptException e){
            //catch 中放的是异常的处理方式
            field.setText("运算错误");
            e.printStackTrace();
        }
    }

    // 实现 ActionListener 接口抽象方法 处理事件 注释不要隔开代码
    // 事件监听 
    @Override
    public void actionPerformed(ActionEvent a) {
        //此处可以捕获到 ActionListener 监听的事件
        //System.out.println(a.getSource());
        //获取被点击按钮  或者按钮的文字
        Object source = a.getSource();
        if (source instanceof JButton) {
            JButton btn = (JButton) source; 
            String text = btn.getText();
            //System.out.println(text);
            //处理对应按键文字
            setBtnText(text);
        }

    }

    public static void main(String[] args) {
        // System.out.println("hello,Calculator");
        // 创建类的对象  线程不安全
        //new Calculator();
        //是Java Swing 开发中确保线程安全的核心代码
        /*
        // EDT 线程保障
        // Swing 要求所有 GUI 操作（组件创建、属性修改、事件处理）必须在 Event Dispatch Thread (EDT) 执行
        // 这里代码通过invokeLater 将 Calculator 类的实例化操作（即 GUI 初始化）提交到 EDT 队列，确保线程安全。
        // 异步执行机制
        // invokeLater 会将传入的 Runnable 任务（此处为 Calculator::new 方法引用）放入 EDT 的任务队列，
        // 由 EDT按顺序执行。这避免了直接操作 GUI 导致的线程竞争问题。
        */
        SwingUtilities.invokeLater(Calculator::new);
    }
}
